#include <math.h>
#include "complex.h"

double abs(complex x) { return sqrt(x.real() * x.real() + x.imag() * x.imag()); }
double norm(complex x) { return x.real() * x.real() + x.imag() * x.imag(); }
double real(complex x) { return x.real(); }
double imag(complex x) { return x.imag(); }
complex &complex::operator+=(complex x)
{
    re += x.re;
    im += x.im;
    return *this;
}
complex &complex::operator+=(double x)
{
    re += x;
    return *this;
}
complex &complex::operator-=(complex x)
{
    re -= x.re;
    im -= x.im;
    return *this;
}
complex &complex::operator-=(double x)
{
    re -= x;
    return *this;
}
complex &complex::operator*=(complex x)
{
    double temp;
    temp = re * x.re - im * x.im;
    im = re * x.im + im * x.re;
    re = temp;
    return *this;
}
complex &complex::operator*=(double x)
{
    re *= x;
    im *= x;
    return *this;
}
complex &complex::operator/=(complex x)
{
    double temp1, temp2;
    temp1 = x.re * x.re + x.im * x.im;
    temp2 = re * x.re + im * x.im;
    im = (x.re * im - re * x.im) / temp1;
    re = temp2 / temp1;
    return *this;
}
complex &complex::operator/=(double x)
{
    re /= x;
    im /= x;
    return *this;
}
complex operator+(complex x, complex y)
{
    complex z = x;
    z += y;
    return z;
}
complex operator+(double x, complex y)
{
    complex z = y;
    z += x;
    return z;
}
complex operator+(complex x, double y)
{
    complex z = x;
    z += y;
    return z;
}
complex operator-(complex x) { return complex(-x.real(), -x.imag()); }
complex operator-(complex x, complex y)
{
    complex z = x;
    z -= y;
    return z;
}
complex operator-(double x, complex y)
{
    complex z = -y;
    z += x;
    return z;
}
complex operator-(complex x, double y)
{
    complex z = x;
    z -= y;
    return z;
}
complex operator*(complex x, complex y)
{
    complex z = x;
    z *= y;
    return z;
}
complex operator*(double x, complex y)
{
    complex z = y;
    z *= x;
    return z;
}
complex operator*(complex x, double y)
{
    complex z = x;
    z *= y;
    return z;
}
complex operator/(complex x, complex y)
{
    complex z = x;
    z /= y;
    return z;
}
complex operator/(double x, complex y)
{
    complex z = complex(x, 0.0);
    z /= y;
    return z;
}
complex operator/(complex x, double y)
{
    complex z = x;
    z /= y;
    return z;
}
complex exp_im(double a) { return complex(cos(a), sin(a)); }
double arg(complex x)
{
    double a = abs(x), ph, pi = 3.14159265358979323846;
    if (a < 1e-200)
        return 0;
    else
    {
        if (x.real() > 0)
            ph = asin(x.imag() / a);
        else
        {
            if (x.imag() > 0)
                ph = pi - asin(x.imag() / a);
            else
                ph = -pi - asin(x.imag() / a);
        }
        return ph;
    }
}
complex conj(complex x) { return complex(x.real(), -x.imag()); }
complex exp(complex x) { return complex(exp(x.real()) * cos(x.imag()), exp(x.real()) * sin(x.imag())); }
complex log(complex x) { return complex(log(norm(x)) / 2., arg(x)); }
complex sqrt(complex x)
{
    double temp1 = sqrt(abs(x)), temp2 = arg(x) / 2;
    return complex(temp1 * cos(temp2), temp1 * sin(temp2));
}
complex pow(complex x, complex q) { return exp(q * log(x)); }
complex pow(complex x, double q) { return exp(q * log(x)); }
complex sin(complex x)
{
    double temp1 = exp(-x.imag()), temp2 = exp(x.imag());
    return complex(sin(x.real()) * (temp1 + temp2) / 2., cos(x.real()) * (temp2 - temp1) / 2.);
}
complex cos(complex x)
{
    double temp1 = exp(-x.imag()), temp2 = exp(x.imag());
    return complex(cos(x.real()) * (temp1 + temp2) / 2., sin(x.real()) * (temp1 - temp2) / 2.);
}
complex tan(complex x) { return sin(x) / cos(x); }
complex asin(complex x)
{
    complex temp = (complex(-x.imag(), x.real()) + sqrt(1 - x * x));
    return complex(arg(temp), -log(norm(temp)) / 2.);
}
complex acos(complex x)
{
    complex temp = (x + sqrt(x * x - 1));
    return complex(arg(temp), -log(norm(temp)) / 2.);
}
complex atan(complex x)
{
    complex temp = complex(1 - x.imag(), x.real()) / complex(1 + x.imag(), -x.real());
    return complex(arg(temp) / 2., -log(norm(temp)) / 4.);
}
complex sinh(complex x) { return (exp(x) - exp(-x)) / 2.; }
complex cosh(complex x) { return (exp(x) + exp(-x)) / 2.; }
complex tanh(complex x) { return (exp(x) - exp(-x)) / (exp(x) + exp(-x)); }
complex asinh(complex x) { return log(x + sqrt(x * x + 1)); }
complex acosh(complex x) { return log(x + sqrt(x * x - 1)); }
complex atanh(complex x) { return log((1 + x) / (1 - x)) / 2.; }
